package com.springmvc.controller;

import com.springmvc.service.DeferredResultQueue;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @author lzy
 * @version v1.0
 * Create DateTime: 2018/12/11 20:37
 */
@Controller
public class AsyncController {

    @ResponseBody
    @RequestMapping("/createOrder")
    public DeferredResult<Object> createOrder() {
        DeferredResult<Object> deferredResult = new DeferredResult<>((long) 3000, "create fail");
        DeferredResultQueue.save(deferredResult);
        return deferredResult;
    }

    @ResponseBody
    @RequestMapping("/createOrderManual")
    public String success() {
        //创建订单
        String order = UUID.randomUUID().toString();
        DeferredResult<Object> result = DeferredResultQueue.get();
        result.setResult(order);
        return "success=====>" + order;
    }

    /**
     * 1.控制器返回Callable
     * 2.SpringMVC异步处理，将Callable提交到TaskExecutor，使用一个隔离的线程进行执行
     * 3.DispatcherServlet和所有的filter退出web容器的线程，但是response保持打开状态
     * 4.Callable返回结果，SpringMVC将请求重新派发给容器，回复之前的处理
     * 5.根据Callable返回的结果，SpringMVC继续进行视图渲染流程等（从收请求-视图渲染）
     * <p>
     * preHandle...
     * 主线程开始Thread[http-nio-6080-exec-6,5,main]
     * 主线程结束Thread[http-nio-6080-exec-6,5,main]
     * ----------DispatcherServlet和所有的filter退出web容器的线程--------
     * ----------等待Callable执行------------
     * 副线程开始Thread[MvcAsync1,5,main]
     * 副线程结束Thread[MvcAsync1,5,main]
     * ----------Callable执行完成------------
     * preHandle... /webapp/async01
     * postHandle... Callable的返回值就是目标方法的返回值
     * afterCompletion...
     * <p>
     * 异步拦截器：
     * ①原生API的AsyncListener
     * ②SpringMVC：实现AsyncHandlerInterceptor
     *
     * @return
     */
    @ResponseBody
    @RequestMapping("/async01")
    public Callable<String> async01() {
        System.out.println("主线程开始" + Thread.currentThread());
        Callable<String> callable = () -> {
            System.out.println("副线程开始" + Thread.currentThread());
            TimeUnit.SECONDS.sleep(2);
            System.out.println("副线程结束" + Thread.currentThread());
            return "Callable<String> async01";
        };
        System.out.println("主线程结束" + Thread.currentThread());
        return callable;
    }
}
